﻿using System;
using System.Collections.Generic;
using System.Data.Services.Client;
using System.Diagnostics;
using System.Linq;
using nRoute.Components;
using nRoute.Components.Composition;
using nRoute.Navigation.Mapping;
using nRoute.Samples.Netflix.Data;
using nRoute.Samples.Netflix.Data.Catalog;
using nRoute.Samples.Netflix.Views;
using nRoute.ViewModels;

namespace nRoute.Samples.Netflix.ViewModels
{
    [DefineNavigationContent("Content/Netflix/Genres/", typeof(GenresListingView))]
    [MapViewModel(typeof(GenresListingView))]
    public class GenresListingViewModel 
        : NavigationViewModelBase, ISupportSearching
    {
        private const string GENRES_KEY = "GenresKey";
        private const string SEARCH_KEY = "SearchKey";

        private NetflixDataContext _catalog;
        private DataServiceCollection<Genre> _genres; 

        [ResolveConstructor]
        public GenresListingViewModel(NetflixDataContext context)
        {
            _catalog = context;
        }

#region Properties

        public IEnumerable<Genre> Genres 
        {
            get 
            {
                if (_genres == null && !IsLoading)
                {
                    LoadGenres();
                    return Enumerable.Empty<Genre>();
                }

                // note search here is basically just a filter, as we pre-load all the genres on the first go..
                return (SearchText == null) ? _genres : _genres.Where((g) => g.Name.IndexOf(SearchText, StringComparison.InvariantCultureIgnoreCase) != -1); 
            }
        }

        public bool IsLoading { get; private set; }

        public string SearchText { get; private set; }

#endregion

#region ISearachable Implementation

        public void Search(string searchText)
        {
            if (string.IsNullOrWhiteSpace(searchText)) throw new ArgumentNullException("searchText");

            SearchText = searchText;
            NotifyPropertyChanged(() => SearchText);
            NotifyPropertyChanged(() => IsSearching);
            NotifyPropertyChanged(() => Genres);
        }

        public bool IsSearching
        {
            get { return (!string.IsNullOrWhiteSpace(this.SearchText)); }
        }

        public void CancelSearch()
        {
            SearchText = null;
            NotifyPropertyChanged(() => SearchText);
            NotifyPropertyChanged(() => IsSearching);
            NotifyPropertyChanged(() => Genres);
        }

#endregion

#region Overrides

        protected override void OnRestoreState(ParametersCollection state)
        {
            if (state != null && state.ContainsKey(GENRES_KEY))
            {             
                _genres = (DataServiceCollection<Genre>)state[GENRES_KEY];
                _genres.LoadCompleted += Genres_LoadCompleted;

                this.SearchText = Convert.ToString(state[SEARCH_KEY]);
                NotifyPropertyChanged(() => IsSearching);

                if (_genres.Count == 0) LoadGenres();
            }
        }

        protected override ParametersCollection OnSaveState()
        {
            if (_genres != null)
            {
                _genres.LoadCompleted -= Genres_LoadCompleted;
                return new ParametersCollection()  
                {
                    new Parameter(GENRES_KEY, _genres),
                    new Parameter(SEARCH_KEY, this.SearchText)
                };
            }
            else
            {
                return null;
            }
        }

#endregion
        
#region Helpers

        private void LoadGenres()
        {
            if (_genres == null)
            {
                _genres = new DataServiceCollection<Genre>();
                _genres.LoadCompleted += Genres_LoadCompleted;
            }

            IsLoading = true;
            NotifyPropertyChanged(() => IsLoading);

            // we load everything 
            var _query = (from g in _catalog.Genres
                          orderby g.Name
                          select g).OrderBy((g) => g.Name);

            try
            {
                _genres.LoadAsync(_query);
            }
            catch
            {
                // the problem is to Cancel any existing request we need to switch to the BegingXX API                
                Debugger.Break();

                // reset
                _genres.LoadCompleted -= Genres_LoadCompleted;
                _genres = null;
                LoadGenres();
                NotifyPropertyChanged(() => Genres);
            }
        }

        private void Genres_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
            IsLoading = false;
            NotifyPropertyChanged(() => IsLoading);
            NotifyPropertyChanged(() => Genres);
        }

#endregion

    }
}